PHP 의 배열 을 깊이 이해 하기(순 서 를 옮 겨 다 니 기)  Laruence 오리지널

5201 단어 배열순서의
PHP 의 배열 이 foreach 로 접근 하면 옮 겨 다 니 는 순서 가 고정 되 어 있 느 냐 는 질문 이 자주 있 습 니 다.어떤 순서 로 옮 겨 다 닐 까요?예 를 들 어
 
<?php
$arr['laruence'] = 'huixinchen';
$arr['yahoo'] = 2007;
$arr['baidu'] = 2008;
foreach ($arr as $key => $val) {
// ?
}
예 를 들 어
 
<?php
$arr[2] = 'huixinchen';
$arr[1] = 2007;
$arr[0] = 2008;
foreach ($arr as $key => $val) {
// ?
}
이 문 제 를 완전히 이해 하려 면 먼저 PHP 배열 의 내부 실현 구 조 를 알 아야 한다 고 생각 합 니 다.또한 선형 스 트 리밍 과 무 작위 접근 을 지원 합 니 다.이전 글 에서 도 논 의 했 듯 이 PHP 의 HASH 알고리즘 을 바탕 으로 우 리 는 진일보 한 연장 을 했 습 니 다.Hash Table 을 인식 하기 전에 먼저 Hash Table 의 구조 정 의 를 보 여 주 었 습 니 다.저 는 주석 을 달 아 여러분 이 이해 할 수 있 도록 해 주 었 습 니 다.
 
typedef struct _hashtable {
uint nTableSize; /* , Hash */
uint nTableMask; /* nTableSize -1, */
uint nNumOfElements; /* HashTable */
ulong nNextFreeElement; /* */
Bucket *pInternalPointer; /* , reset, current */
Bucket *pListHead; /* , */
Bucket *pListTail; /* , */
Bucket **arBuckets; /* */
dtor_func_t pDestructor;/* ( ) */
zend_bool persistent;
unsigned char nApplyCount; /* */
zend_bool bApplyProtection;
#if ZEND_DEBUG
int inconsistent;
#endif
} HashTable;
nApply Count 의 의미 에 대해우 리 는 하나의 예 를 통 해 알 수 있다.
 
<?php
$arr = array(1,2,3,4,5,);
$arr[] = &$arr;

var_export($arr); //Fatal error: Nesting level too deep - recursive dependency?
이 필드 는 순환 인용 으로 인 한 무한 순환 을 예방 하기 위해 설립 된 것 이다.위의 구 조 를 보면 알 수 있 듯 이 HashTable 에 있어 관건 적 인 요 소 는 바로 arBuckets 이다.이것 은 실제 저 장 된 용기 이다.우 리 는 그의 구조 정 의 를 살 펴 보 자.
 
typedef struct bucket {
ulong h; /* /hash */
uint nKeyLength; /* */
void *pData; /* */
void *pDataPtr; /* */
struct bucket *pListNext; /* , */
struct bucket *pListLast; /* , */
struct bucket *pNext; /* */
struct bucket *pLast; /* */
char arKey[1]; /* , */
} Bucket;
우 리 는 마지막 요 소 를 알 수 있다.이것 은 flexible array 기법 으로 메모리 절약 과 초기 화 에 편리 한 방법 입 니 다.관심 이 있 는 친 구 는 google flexible array.h 는 요소 의 Hash 값 입 니 다.디지털 색인 요소 에 대해 h 는 직접 색인 값(nKeyLength=0 을 통 해 디지털 색인 임 을 표시 합 니 다)입 니 다.문자열 색인 에 있어 색인 값 은 arkey 에 저 장 됩 니 다.색인 길 이 는 nKeyLength 에 저 장 됩 니 다.Bucket 에서 실제 데 이 터 는 pData 포인터 가 가리 키 는 메모리 블록 에 저 장 됩 니 다.보통 이 메모리 블록 은 시스템 에서 따로 분 배 됩 니 다.그러나 한 가지 예외 가 있 습 니 다.Bucket 에 저 장 된 데이터 가 지침 일 때 HashTable 은 시스템 에 이 지침 을 저장 할 공간 을 따로 요청 하지 않 고 이 지침 을 pDataPtr 에 직접 저장 한 다음 pData 를 이 구조 구성원 의 주 소 를 가리 키 는 것 입 니 다.이렇게 하면 효율 을 높이 고 메모리 조각 을 줄 일 수 있다.이로써 우 리 는 PHP Hash Table 디자인 의 정교 한 점 을 볼 수 있다.Bucket 의 데이터 가 지침 이 아니라면 pDataPtr 는 NULL(이 단락 은 Altair 에서 온'Zend HashTable 상세 설명')입 니 다.위의 HashTable 구 조 를 결합 하여 HashTable 의 총 구조 도 를 설명 하 겠 습 니 다.HashTable 의 pListhHead 는 선형 목록 형식의 첫 번 째 요 소 를 가리 키 고 위의 그림 은 요소 1 이 며 pListTail 은 마지막 요소 0 을 가리 키 고 있 습 니 다.그리고 모든 요소 에 대해 pList Next 는 빨간색 라인 이 그 려 진 선형 구조의 다음 요소 이 고 pList Last 는 이전 요소 입 니 다.pInternal Pointer 는 현재 내부 포인터 의 위 치 를 가리 키 며 배열 을 순서대로 옮 겨 다 닐 때 이 지침 은 현재 의 원 소 를 가 리 킵 니 다.선형(순서)을 옮 겨 다 닐 때 pList Head 부터 시작 합 니 다.Bucket 에 있 는 pListNext/ListLast 를 따라 이동 pInternalpointer 에 따라 모든 요 소 를 선형 으로 옮 겨 다 닙 니 다.예 를 들 어 foreach 에 대해 서 는 생 성 된 opcode 서열 을 보면 foreach 전에 먼저 FE 가 있 음 을 알 수 있 습 니 다.RESET 은 배열 의 내부 지침,즉 pInternalPointer 를 리 셋 합 니 다.(foreach 에 대해 서 는 PHP 원 리 를 깊이 이해 하 는 foreach 를 참조 할 수 있 습 니 다)그리고 매번 FE 를 통 해FETCH 는 pInternal Pointer 를 증가 시 켜 서 순 서 를 옮 겨 다 니 는 것 을 실현 합 니 다.유사 한 것 은 우리 가'each/next 시리즈 함수'를 사용 하여 옮 겨 다 닐 때 도 모 바 일 배열 의 내부 지침 을 통 해 순 서 를 옮 겨 다 니 는 것 입 니 다.여기 서 문제 가 있 습 니 다.예 를 들 어
 
<?php
$arr = array(1,2,3,4,5);
foreach ($arr as $v) {
//
}

while (list($key, $v) = each($arr)) {
//
}
?>
제 가 방금 소개 한 지식 을 알 게 되면 이 문제 도 밝 아 집 니 다.foreach 는 자동 으로 reset 되 기 때 문 입 니 다.while 라 는 것 은 reset 이 되 지 않 기 때문에 foreach 가 끝 난 후에 pInternal Pointer 는 배열 의 맨 끝 을 가리 키 고 while 문 구 는 당연히 접근 할 수 없습니다.해결 방법 은 each 전에 reset 배열 의 내부 지침 입 니 다.무 작위 로 방문 할 때 hash 값 을 통 해 hash 배열 의 머리 지침 위 치 를 확인 합 니 다.그 다음 에 pNext/Last 를 통 해 특징 요 소 를 찾 습 니 다.요 소 를 추가 할 때 요 소 는 같은 Hash 요소 체인 의 머리 와 선형 목록 의 끝 에 삽 입 됩 니 다.즉,요 소 는 선형 으로 옮 겨 다 닐 때 삽 입 된 선후 순서에 따라 옮 겨 다 닙 니 다.이 특수 한 디자인 으로 인해 PHP 에서 디지털 색인 을 사용 할 때 요소 의 선후 순 서 는 추 가 된 순서 로 결 정 됩 니 다.색인 순서 가 아 닙 니 다.즉,PHP 에서 배열 을 옮 겨 다 니 는 순 서 는 요소 의 추가 와 선후 가 있 습 니 다.그러면 지금 우 리 는 글 의 시작 부분 에 있 는 문제 의 출력 은:
 
huixinchen
2007
2008
이 므 로 디지털 색인 배열 에서 색인 크기 에 따라 옮 겨 다 니 려 면 foreach
 
for($i=0,$l=count($arr); $i<$l; $i++) {
// , ( )
}
원문 이 아 닌 for 를 사용 해 야 합 니 다.http://www.laruence.com/2009/08/23/1065.html

좋은 웹페이지 즐겨찾기